// server_main.cpp
#include "nim.h"
#include <iostream>
#include <string>
#include <WinSock2.h>
#include <string>
#include <sstream>

#define YES "YES"
#define YES_LENGTH 3
#define MAXIPBUF  20

void sendInitialSetup(SOCKET s,std::string setup)
{
	char * sendMessage = new char[setup.length()+1];
	strcpy_s(sendMessage,setup.length()+1,setup.c_str());
	TCP_send(s,sendMessage,setup.length()+1);
	delete [] sendMessage;
}
std::string getSetupFromUser()
{
	int numberOfPiles;
	std::stringstream out;
	std::cout<<"number of piles?"<<std::endl;
	std::cin>>numberOfPiles;
	out<<numberOfPiles;
	for(int i= 0; i < numberOfPiles; i++)
	{
		int numberOfRocks;
		std::cout<<"number of rocks for pile "<<(i+1)<<" ?"<<std::endl;
		std::cin>>numberOfRocks;
		if(numberOfRocks < 10)
		{
			out<<"0";
		}
		out<<numberOfRocks;
	}
	return out.str();
}
bool serverWantsToPlay(std::string opponentName)
{
	std::string result = "f";
	std::cout<<"Accept challenge from "<<opponentName<<std::endl;
	std::cin>>result;
	if (result[0] =='F')
		return false;
	else
	{
		return true;
	}
}
int server_main(int argc, char *argv[], std::string playerName)
{
	SOCKET s;
	char buf[MAX_RECV_BUF];
	char host[MAX_HOST_SIZE];
	char port[MAX_SERVICE_SIZE];
	char response_str[MAX_SEND_BUF];
	
	s = passivesock(NIM_UDPPORT,"udp");

	std::cout << std::endl << "Waiting for a challenge..." << std::endl;
	int len = UDP_recv(s, buf, MAX_RECV_BUF, host, port);	// Blocking function call!

	bool finished = false;
	while (!finished) {
		
		if ( strcmp(buf,NIM_QUERY) == 0) {
			// Respond to name query
			//strcpy_s(response_str,NIM_NAME);
			strcpy_s(response_str,playerName.c_str());
			UDP_send(s, response_str, strlen(response_str)+1, host, port);

		} else if ( strncmp(buf,NIM_CHALLENGE,strlen(NIM_CHALLENGE)) == 0) {
			// Received a challenge  

			char *startOfName = strstr(buf,NIM_CHALLENGE);
			if (startOfName != NULL) {
				std::cout << std::endl << "You have been challenged by " << startOfName+strlen(NIM_CHALLENGE) << std::endl;
			}
			bool isUserWillingToPlay = serverWantsToPlay(startOfName+strlen(NIM_CHALLENGE));


			// default service name or port number
			sockaddr_in   csin;					// holds client's socket information
			SOCKET       lsock;					// listening socket handle
			SOCKET       csock;					// connected socket handle
			int clen = sizeof(csin);			// size of client's sockaddr_in struct
			char ip_addr[MAXIPBUF];				// IP address of client
				

			if (isUserWillingToPlay)
			{
				// Create a listening socket named lsock
				lsock = passivesock(NIM_TCPPORT,"tcp");
				
				strcpy_s(buf,YES);
				UDP_send(s,buf,strlen(buf)+1,host,port);

			}
			
			int status = wait(s,5,0);
			if (status > 0 && UDP_recv(s, buf, MAX_RECV_BUF, host, port) > 0  && strcmp(buf,NIM_GREAT)==0)
			{			
				// close UDP socket
				closesocket(s);

				// start receiving tcp connection 
				if (lsock != INVALID_SOCKET) {
					std::cout << "Waiting for connections..." << std::endl;
					while (true) { //Accept connections "forever" 
						csock = accept(lsock,(LPSOCKADDR) &csin, &clen);
						if (csock == INVALID_SOCKET) {
							std::cout << "Unable to accept connection request" << std::endl;
						}
						else {
							strcpy_s(ip_addr, MAXIPBUF, inet_ntoa(csin.sin_addr) );
							// Play the game.  You are the 'O' player

							std::string setup = getSetupFromUser();
							sendInitialSetup(csock,setup);
							int winner = playNim(csock, (char*) playerName.c_str(), host, NIM_TCPPORT, SERVER_PLAYER,setup);
						}
						if (csock != INVALID_SOCKET)
						{
							shutdown(csock,1);
							closesocket(csock);
						}
					}
				}
			}else 
			{
				closesocket(lsock);
			}
			
			
			
			finished = true;
		}

		if (!finished) {
			char previous_buf[MAX_RECV_BUF];		strcpy_s(previous_buf,buf);
			char previous_host[MAX_HOST_SIZE];		strcpy_s(previous_host,host);
			char previous_port[MAX_SERVICE_SIZE];	strcpy_s(previous_port,port);

			// Check for duplicate datagrams (can happen if broadcast enters from multiple ethernet connections)
			bool newDatagram = false;
			int status = wait(s,1,0);	// We'll wait a second to see if we receive another datagram
			while (!newDatagram && status > 0) {
				len = UDP_recv(s, buf, MAX_RECV_BUF, host, port);
				if (strcmp(buf,previous_buf)==0 &&		// If this datagram is identical to previous one, ignore it.
					strcmp(host,previous_host)==0 && 
					strcmp(port,previous_port)==0) {
						status = wait(s,1,0);			// Wait another second (still more copies?)
				} else {
					newDatagram = true;		// if not identical to previous one, keep it!
				}
			}

			// If we waited one (or more seconds) and received no new datagrams, wait for one now.
			if (!newDatagram ) {
				len = UDP_recv(s, buf, MAX_RECV_BUF, host, port);
			}
		}
	}
	closesocket(s);

	return 0;
}